package com.gitee.wsl.time

import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.Month
import kotlinx.datetime.number
import kotlin.time.ExperimentalTime


/**
 *
 * Represents a quarter (in most cases of a year).
 *
 * @author  Meno Hochschild
 */
/*[deutsch]
 * <p>Repr&auml;sentiert ein Quartal (meist eines Jahres). </p>
 *
 * @author  Meno Hochschild
 */
enum class Quarter {
    //~ Statische Felder/Initialisierungen --------------------------------
    /**
     *
     * First quarter with the numerical value `1`.
     */
    /*[deutsch]
     * <p>Erstes Quartal mit dem numerischen Wert {@code 1}. </p>
     */
    Q1,

    /**
     *
     * Second quarter with the numerical value `2`.
     */
    /*[deutsch]
     * <p>Zweites Quartal mit dem numerischen Wert {@code 2}. </p>
     */
    Q2,

    /**
     *
     * Third quarter with the numerical value `3`.
     */
    /*[deutsch]
     * <p>Drittes Quartal mit dem numerischen Wert {@code 3}. </p>
     */
    Q3,

    /**
     *
     * Last quarter with the numerical value `4`.
     */
    /*[deutsch]
     * <p>Letztes Quartal mit dem numerischen Wert {@code 4}. </p>
     */
    Q4;

    /**
     *
     * Gets the corresponding numerical value.
     *
     * @return  int (Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4)
     */
    val value: Int
        get() = ordinal + 1

    /**
     *
     * Rolls to the next quarter.
     *
     *
     * The result is `Q1` if this method is applied on `Q4`.
     *
     * @return  next quarter rolling at last quarter
     */
    /*[deutsch]
     * <p>Ermittelt das n&auml;chste Quartal. </p>
     *
     * <p>Auf {@code Q4} angewandt ist das Ergebnis {@code Q1}. </p>
     *
     * @return  next quarter rolling at last quarter
     */
    operator fun next(): Quarter {
        return roll(1)
    }

    /**
     *
     * Rolls to the previous quarter.
     *
     *
     * The result is `Q4` if this method is applied on `Q1`.
     *
     * @return  previous quarter rolling at first quarter
     */
    /*[deutsch]
     * <p>Ermittelt das vorherige Quartal. </p>
     *
     * <p>Auf {@code Q1} angewandt ist das Ergebnis {@code Q4}. </p>
     *
     * @return  previous quarter rolling at first quarter
     */
    fun previous(): Quarter {
        return roll(-1)
    }

    /**
     *
     * Rolls by given amount of quarters.
     *
     * @param   quarters    count of quarters (maybe negative)
     * @return  result of rolling operation
     */
    /*[deutsch]
     * <p>Rollt um die angegebene Anzahl von Quartalen vor oder
     * zur&uuml;ck. </p>
     *
     * @param   quarters    count of quarters (maybe negative)
     * @return  result of rolling operation
     */
    fun roll(quarters: Int): Quarter {
        return valueOf((ordinal + (quarters % 4 + 4)) % 4 + 1
        )
    }

    companion object {
        private val ENUMS = entries.toTypedArray() // Cache
        //~ Methoden ----------------------------------------------------------
        /**
         *
         * Gets the enum-constant which corresponds to the given numerical
         * value.
         *
         * @param   quarter     value in the range [1-4]
         * @return  enum
         * @throws  IllegalArgumentException if given argument is out of range
         */
        /*[deutsch]
     * <p>Liefert die zum chronologischen Integer-Wert passende
     * Enum-Konstante. </p>
     *
     * @param   quarter     value in the range [1-4]
     * @return  enum
     * @throws  IllegalArgumentException if given argument is out of range
     */
        fun valueOf(quarter: Int): Quarter {
            require(!(quarter !in 1..4)) { "Out of range: $quarter" }
            return ENUMS[quarter - 1]
        }
    }
}


val LocalDate.quarter get() = ((month.number -1) / 3) + 1

val LocalDateTime.quarter get() = ((month.number -1) / 3) + 1

@OptIn(ExperimentalTime::class)
val YearMonth.quarter get() = ((monthNumber - 1 ) / 3) + 1

val Month.quarter get() = ((number - 1) / 3) + 1